package com.ws.gold.swing;

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class LineChartPanel extends JPanel {

    private List<String> xLabels;
    private List<Double> yValues;
    private double minVal;
    private double maxVal;
    private int hoverIndex = -1, hoverX, hoverY;
    private boolean dragging = false;
    private Point dragStart, dragEnd;

    public LineChartPanel(List<String> xLabels, List<Double> yValues) {
        updateData(xLabels, yValues);

        addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseMoved(MouseEvent e) {
                int mouseX = e.getX();
                int mouseY = e.getY();
                int baseY = getHeight() - 50;
                int xStep = (getWidth() - 100) / (xLabels.size() - 1);

                for (int i = 0; i < xLabels.size(); i++) {
                    int x = 50 + i * xStep;
                    int y = baseY - (int)((yValues.get(i) - minVal) * (getHeight() - 100) / (maxVal - minVal));

                    if (Math.abs(mouseX - x) < 6 && Math.abs(mouseY - y) < 6) {
                        hoverIndex = i;
                        hoverX = x;
                        hoverY = y;
                        repaint();
                        return;
                    }

                    if (i < xLabels.size() - 1) {
                        int x2 = 50 + (i + 1) * xStep;
                        int y2 = baseY - (int)((yValues.get(i + 1) - minVal) * (getHeight() - 100) / (maxVal - minVal));
                        if (isNearLine(mouseX, mouseY, x, y, x2, y2)) {
                            hoverIndex = (Math.abs(mouseX - x) < Math.abs(mouseX - x2)) ? i : i + 1;
                            hoverX = 50 + hoverIndex * xStep;
                            hoverY = baseY - (int)((yValues.get(hoverIndex) - minVal) * (getHeight() - 100) / (maxVal - minVal));
                            repaint();
                            return;
                        }
                    }
                }
                hoverIndex = -1;
                repaint();
            }

            public void mouseDragged(MouseEvent e) {
                dragEnd = e.getPoint();
                repaint();
            }
        });

        addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                dragging = true;
                dragStart = e.getPoint();
            }

            public void mouseReleased(MouseEvent e) {
                dragging = false;
                dragEnd = e.getPoint();
                repaint();
                handleSelection();
            }
        });
    }

    public void updateData(List<String> newX, List<Double> newY) {
        this.xLabels = new ArrayList<>(newX);
        this.yValues = new ArrayList<>(newY);
        if (!newY.isEmpty()) {
            maxVal = Collections.max(newY);
            minVal = Collections.min(newY);
            double range = maxVal - minVal;
            double padding = Math.max(0.5, range * 0.2);
            maxVal += padding;
            minVal -= padding;
        }
        repaint();
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        drawAxes(g);
        drawLines(g);
        if (hoverIndex != -1) drawTooltip(g);
        if (dragStart != null && dragEnd != null) drawDragBox(g);
    }

    private void drawAxes(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        int width = getWidth(), height = getHeight();

        g2.setColor(Color.GRAY);
        g2.setStroke(new BasicStroke(2));
        g2.drawLine(50, height - 50, width - 50, height - 50);
        g2.drawLine(50, height - 50, 50, 50);

        for (int i = 0; i <= 5; i++) {
            double val = minVal + (maxVal - minVal) * i / 5;
            int y = height - 50 - (int)((val - minVal) * (height - 100) / (maxVal - minVal));
            g2.drawLine(45, y, 55, y);
            g2.drawString(String.format("%.2f", val), 10, y + 5);
        }

        int xStep = (width - 100) / (xLabels.size() - 1);
        int labelStep = Math.max(1, xLabels.size() / 10);
        for (int i = 0; i < xLabels.size(); i++) {
            int x = 50 + i * xStep;
            g2.drawLine(x, height - 45, x, height - 55);
            if (i % labelStep == 0) {
                g2.drawString(xLabels.get(i), x - 15, height - 30);
            }
        }
    }

    private void drawLines(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(new Color(66, 133, 244));
        g2.setStroke(new BasicStroke(2));
        int xStep = (getWidth() - 100) / (xLabels.size() - 1);
        int baseY = getHeight() - 50;

        for (int i = 0; i < yValues.size() - 1; i++) {
            int x1 = 50 + i * xStep;
            int y1 = baseY - (int)((yValues.get(i) - minVal) * (getHeight() - 100) / (maxVal - minVal));
            int x2 = 50 + (i + 1) * xStep;
            int y2 = baseY - (int)((yValues.get(i + 1) - minVal) * (getHeight() - 100) / (maxVal - minVal));
            g2.drawLine(x1, y1, x2, y2);
            g2.fillOval(x1 - 3, y1 - 3, 6, 6);
        }
        int xLast = 50 + (xLabels.size() - 1) * xStep;
        int yLast = baseY - (int)((yValues.get(yValues.size() - 1) - minVal) * (getHeight() - 100) / (maxVal - minVal));
        g2.fillOval(xLast - 3, yLast - 3, 6, 6);
    }

    private void drawTooltip(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        String msg = xLabels.get(hoverIndex) + ": " + yValues.get(hoverIndex);
        int width = g.getFontMetrics().stringWidth(msg) + 10;
        g2.setColor(Color.WHITE);
        g2.fillRect(hoverX + 10, hoverY - 25, width, 20);
        g2.setColor(Color.BLACK);
        g2.drawRect(hoverX + 10, hoverY - 25, width, 20);
        g2.drawString(msg, hoverX + 15, hoverY - 10);
        g2.setColor(Color.RED);
        g2.fillOval(hoverX - 5, hoverY - 5, 10, 10);
    }

    private void drawDragBox(Graphics g) {
        Graphics2D g2 = (Graphics2D) g;
        int x = Math.min(dragStart.x, dragEnd.x);
        int y = Math.min(dragStart.y, dragEnd.y);
        int w = Math.abs(dragEnd.x - dragStart.x);
        int h = Math.abs(dragEnd.y - dragStart.y);
        g2.setColor(new Color(0, 120, 215, 80));
        g2.fillRect(x, y, w, h);
        g2.setColor(Color.BLUE);
        g2.drawRect(x, y, w, h);
    }

    private void handleSelection() {
        int xMin = Math.min(dragStart.x, dragEnd.x);
        int xMax = Math.max(dragStart.x, dragEnd.x);
        int xStep = (getWidth() - 100) / (xLabels.size() - 1);

        for (int i = 0; i < xLabels.size(); i++) {
            int x = 50 + i * xStep;
            if (x >= xMin && x <= xMax) {
                System.out.println("选中：" + xLabels.get(i) + " -> " + yValues.get(i));
            }
        }
    }

    private boolean isNearLine(int px, int py, int x1, int y1, int x2, int y2) {
        double distance = pointToSegmentDistance(px, py, x1, y1, x2, y2);
        return distance < 6;
    }

    private double pointToSegmentDistance(int px, int py, int x1, int y1, int x2, int y2) {
        double dx = x2 - x1;
        double dy = y2 - y1;
        if (dx == 0 && dy == 0) return Math.hypot(px - x1, py - y1);
        double t = ((px - x1) * dx + (py - y1) * dy) / (dx * dx + dy * dy);
        t = Math.max(0, Math.min(1, t));
        double projX = x1 + t * dx;
        double projY = y1 + t * dy;
        return Math.hypot(px - projX, py - projY);
    }
}
